﻿using GarboDev;
using System;
using static Thumb;
using static OptimeGBA.Bits;
using Bool =System.Boolean;

//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define ARCH_VER ARCH_V_4
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define _bitm(v, a, b, size) (((v) << ((size) - (b)-1)) >> ((size) - (b)-1 + (a)))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define bit1(v, a) (((v) >> (a)) & 0b1)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define bitm64(v, a, b) _bitm(v, a, b, 64)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define bitm(v, a, b) _bitm(v, a, b, 32)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define bitm16(v, a, b) _bitm(v, a, b, 16)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define bitm8(v, a, b) _bitm(v, a, b, 8)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define bitm4(v, a, b) _bitm(v, a, b, 4)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define val_bits(val) ((uint32)sizeof(val) << 3)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define sign_extend(val, val_bits) (((int32)((val) << (32 - (val_bits)))) >> (32 - (val_bits)))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define sign_extend_e(val) (((int32)((val) << (32 - val_bits(val)))) >> (32 - val_bits(val)))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define inst_bm(from, to) bitm(inst, from, to)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define inst_b1(pos) bit1(inst, pos)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define inst_b4(from) inst_bm(from, from + 3)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define inst_b8(from) inst_bm(from, from + 7)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define inst_b16(from) inst_bm(from, from + 15)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define inst_b24(from) inst_bm(from, from + 23)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define println(fmt, ...) printf(fmt, ##__VA_ARGS__); printf("\n")
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define logd(fmt, ...) printf("[DEBUG] "); println(fmt, ##__VA_ARGS__)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define loge(fmt, ...) printf("[ERROR] "); println(fmt, ##__VA_ARGS__)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define logw(fmt, ...) printf("[WARN]  "); println(fmt, ##__VA_ARGS__)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define logi(fmt, ...) printf("[LOG]   "); println(fmt, ##__VA_ARGS__)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define null ((void *)0)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define vmpt_real(type, p) ((type *)((vm->cpu->mem->buffer) + (p)))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define loginst(name, hex) println("[INST]  name=%s, hex=0x%08x", name, hex)
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define loginst(name, hex)




//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define lsl8(val, shift) ((uint8)(val) << (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define asl8(val, shift) ((int8)(val) << (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define lsr8(val, shift) ((uint8)(val) >> (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define asr8(val, shift) ((int8)(val) >> (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define ror8(val, shift) (lsr8(val, shift) | lsl8(val, (8 - (shift))))

//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define lsl16(val, shift) ((uint16)(val) << (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define asl16(val, shift) ((int16)(val) << (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define lsr16(val, shift) ((uint16)(val) >> (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define asr16(val, shift) ((int16)(val) >> (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define ror16(val, shift) (lsr16(val, shift) | lsl16(val, (16 - (shift))))

//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define lsl(val, shift) ((uint32)(val) << (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define asl(val, shift) ((int32)(val) << (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define lsr(val, shift) ((uint32)(val) >> (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define asr(val, shift) ((int32)(val) >> (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define ror(val, shift) (lsr(val, shift) | lsl(val, (32 - (shift))))

//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define lsl64(val, shift) ((uint64)(val) << (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define asl64(val, shift) ((int64)(val) << (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define lsr64(val, shift) ((uint64)(val) >> (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define asr64(val, shift) ((int64)(val) >> (shift))
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define ror64(val, shift) (lsr64(val, shift) | lsl64(val, (64 - (shift))))

//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 NOTE: The following #define macro was replaced in-line:
//ORIGINAL LINE: #define regv(R) (st->registers[R])

public class cpu_psr_t
{
	//31  30  29  28  27  26-25   24  23-20      19-16    15-10     9  8  7  6  5  4-0
	//N   Z   C   V   Q   Res     J   RESERVED   GE[3:0]  RESERVED  E  A  I  F  T  M[4:0]

	public Bool n = false;

    public Bool z = false;
    public Bool c = false;
    public Bool v = false;
    //public bool v;

    public Bool q = false;

    public Bool j = false;
    public uint ge;

	public Bool e = false;
    public Bool a = false;
    public Bool i = false;
    public Bool f = false;
    public Bool t = false;

    public uint mode;

}

//CPU状态
public class cpu_state_t
{
    //public uint[] registers {
    //       get{
    //           foreach (var v in registerss)
    //               if (v == 20292)
    //               {

    //               }
    //           return registerss;
    //       }
    //       set {

    //           registerss = value;
    //       } } //寄存器列表
    public uint[] registers = new uint[16]; //寄存器列表
                                            //public IntPtr[] registers = new IntPtr[16]; //寄存器列表
    public uint[] R
    {
        get { return registers; }
        set { registers = value; }
    }

    //public uint VectorSoftwareInterrupt= 0xFFFF0008;
    public uint VectorSoftwareInterrupt = 0x08;

    public bool Armv5 => OptimeGBA.Arm.Armv5;
    public bool Negative { get { return cpsr.n; } set { cpsr.n = value; } }
    public bool Zero { get { return cpsr.z; } set { cpsr.z = value; } }
    public bool Carry { get { return cpsr.c; } set { cpsr.c = value; } }
    public bool Overflow { get { return cpsr.v; } set { cpsr.v = value; } }
    public bool Sticky { get { return cpsr.q; } set { cpsr.q = value; } }
    public bool IRQDisable    { get { return cpsr.i; } set { cpsr.i = value; } }
    public bool FIQDisable { get { return cpsr.f; } set { cpsr.f = value; } }
    
    public bool ThumbState { get { return cpsr.t; } set { cpsr.t = value; } }
    public uint Mode { get { return cpsr.mode; } set { cpsr.mode = value; } }

    public uint[] Registers
    {
        get { return registers; }
        set { registers = value; }
    }

    public int Cycles = 1;
    public uint CPSR { get; internal set; }
    // CPU mode definitions
    public const uint USR = 0x10;
    public const uint FIQ = 0x11;
    public const uint IRQ = 0x12;
    public const uint SVC = 0x13;
    public const uint ABT = 0x17;
    public const uint UND = 0x1B;
    public const uint SYS = 0x1F;

    // CPSR bit definitions
    public const int N_BIT = 31;
    public const int Z_BIT = 30;
    public const int C_BIT = 29;
    public const int V_BIT = 28;
    public const int I_BIT = 7;
    public const int F_BIT = 6;
    public const int T_BIT = 5;

    public const uint N_MASK = (uint)(1U << N_BIT);
    public const uint Z_MASK = (uint)(1U << Z_BIT);
    public const uint C_MASK = (uint)(1U << C_BIT);
    public const uint V_MASK = (uint)(1U << V_BIT);
    public const uint I_MASK = (uint)(1U << I_BIT);
    public const uint F_MASK = (uint)(1U << F_BIT);
    public const uint T_MASK = (uint)(1U << T_BIT);

    public void SetCPSR(uint val)
    {
        Negative = BitTest(val, 31);
        Zero = BitTest(val, 30);
        Carry = BitTest(val, 29);
        Overflow = BitTest(val, 28);
        Sticky = BitTest(val, 27);

        IRQDisable = BitTest(val, 7);
        FIQDisable = BitTest(val, 6);
        bool newThumbState = BitTest(val, 5);
        if (newThumbState != ThumbState)
        {
            StateChange();
        }
        ThumbState = newThumbState;

        SetMode((Arm7Mode)(val & 0b01111));
    }

    public uint SPSR_fiq;
    public uint SPSR_svc;
    public uint SPSR_abt;
    public uint SPSR_irq;
    public uint SPSR_und;

    public uint GetSPSR()
    {
        switch ((Arm7Mode)Mode)
        {
            case Arm7Mode.FIQ:
            case Arm7Mode.OldFIQ:
                return SPSR_fiq;
            case Arm7Mode.SVC:
            case Arm7Mode.OldSVC:
                return SPSR_svc;
            case Arm7Mode.ABT:
                return SPSR_abt;
            case Arm7Mode.IRQ:
            case Arm7Mode.OldIRQ:
                return SPSR_irq;
            case Arm7Mode.UND:
                return SPSR_und;

        }

        // Error("No SPSR in this mode!");
        return GetCPSR();

    }
    public void SetSPSR(uint set)
    {
        switch ((Arm7Mode)Mode)
        {
            case Arm7Mode.FIQ:
            case Arm7Mode.OldFIQ:
                SPSR_fiq = set;
                return;
            case Arm7Mode.SVC:
            case Arm7Mode.OldSVC:
                SPSR_svc = set;
                return;
            case Arm7Mode.ABT:
                SPSR_abt = set;
                return;
            case Arm7Mode.IRQ:
            case Arm7Mode.OldIRQ:
                SPSR_irq = set;
                return;
            case Arm7Mode.UND:
                SPSR_und = set;
                return;

        }

        SetCPSR(set);

        // Error("No SPSR in this mode!");
    }

    public cpu_psr_t cpsr = new cpu_psr_t(); //cpsr寄存器

	//内存空间
	public memory_t mem;

    public void Write32(uint addr, uint value)
    {
      GlobalMembers.mem_st32(GlobalMembers.vm.cpu.mem, addr, value);
    }

    public void Write16(uint addr, uint value)
    {
        GlobalMembers.mem_st16(GlobalMembers.vm.cpu.mem, addr, value);
    }

    public void Write8(uint addr, uint value)
    {
        GlobalMembers.mem_st8(GlobalMembers.vm.cpu.mem, addr, value);
    }

    internal void LineDebug(string v)
    {
        if(GameStart .isPrint)
           GlobalMembers.loginst(v);
    }

    public static bool CheckOverflowSub(uint val1, uint val2, uint result)
    {
        return ((val1 ^ val2) & ((val1 ^ result)) & 0x80000000) != 0;
    }

    public static bool CheckOverflowAdd(uint val1, uint val2, uint result)
    {
        return (~(val1 ^ val2) & ((val1 ^ result)) & 0x80000000) != 0;
    }

    internal void FlushPipeline()
    {
        if (ThumbState)
        {
            R[15] &= ~1U;
            //R[15] += 2;
            //InstructionCycles += Timing8And16InstrFetch[(R[15] >> 24) & 0xF] * 2U;
            if (GameStart.Ins.TestThumbIndex == 1)
                Thumb.thumb.BeginExecution();
            else
            {
                ThumbCore.thumbCore.ChengeThumb();
                ThumbCore.thumbCore.BeginExecution();
            }

        }
        else
        {
            R[15] &= ~3U;
            //R[15] += 4;
            //InstructionCycles += Timing32InstrFetch[(R[15] >> 24) & 0xF] * 2U;
            if(GameStart.Ins.isGbaArm)
            OptimeGBA.Arm.BeginExecution();
        }


    }

    public  void StateChange()
    {
        //GlobalMembers.isStartThumb = false;
    }

    public bool CheckCondition(uint code)
    {
        // Unconditional execution is most common, do a quick check 
        // instead of going through a slow switch
        if (code == 0xE)
        {
            return true;
        }

        switch (code)
        {
            case 0x0: // Zero, Equal, Z=1
                return Zero;
            case 0x1: // Nonzero, Not Equal, Z=0
                return !Zero;
            case 0x2: // Unsigned higher or same, C=1
                return Carry;
            case 0x3: // Unsigned lower, C=0
                return !Carry;
            case 0x4: // Signed Negative, Minus, N=1
                return Negative;
            case 0x5: // Signed Positive or Zero, Plus, N=0
                return !Negative;
            case 0x6: // Signed Overflow, V=1
                return Overflow;
            case 0x7: // Signed No Overflow, V=0
                return !Overflow;
            case 0x8: // Unsigned Higher, C=1 && Z=0
                return Carry && !Zero;
            case 0x9: // Unsigned Lower or Same
                return !Carry || Zero;
            case 0xA: // Signed Greater or Equal
                return Negative == Overflow;
            case 0xB: // Signed Less Than
                return Negative != Overflow;
            case 0xC: // Signed Greater Than
                return !Zero && Negative == Overflow;
            case 0xD: // Signed less or Equal, Z=1 or N!=V
                return Zero || (Negative != Overflow);
            case 0xE: // Always
                return true;
            case 0xF: // some ARMv5 instructions have 0xF as condition code in encoding
                return true;
        }

        return false;
    }

    internal uint Read32(uint v)
    {
        return GlobalMembers.mem_ld32(GlobalMembers.vm.cpu.mem, v);
    }

    internal uint Read16(uint v)
    {
        return GlobalMembers.mem_ld16(GlobalMembers.vm.cpu.mem, v);
    }

    internal byte Read8(uint v)
    {
        return GlobalMembers.mem_ld8(GlobalMembers.vm.cpu.mem, v);
    }

    internal void ICycle()
    {
      
    }

    public void SetMode(Arm7Mode mode)
    {
        // Bit 4 of mode is always set 
        mode |= (Arm7Mode)0b10000;

        // Store registers based on current mode
        //switch ((Arm7Mode)Mode)
        //{
        //    case Arm7Mode.USR:
        //    case Arm7Mode.SYS: for (uint i = 0; i < 7; i++) Rusr[i] = R[8 + i]; break;
        //    case Arm7Mode.FIQ: for (uint i = 0; i < 7; i++) Rfiq[i] = R[8 + i]; break;
        //    case Arm7Mode.SVC: for (uint i = 0; i < 2; i++) Rsvc[i] = R[13 + i]; break;
        //    case Arm7Mode.ABT: for (uint i = 0; i < 2; i++) Rabt[i] = R[13 + i]; break;
        //    case Arm7Mode.IRQ: for (uint i = 0; i < 2; i++) Rirq[i] = R[13 + i]; break;
        //    case Arm7Mode.UND: for (uint i = 0; i < 2; i++) Rund[i] = R[13 + i]; break;
        //}

        //switch (mode)
        //{
        //    case Arm7Mode.USR:
        //    case Arm7Mode.SYS: for (uint i = 5; i < 7; i++) R[8 + i] = Rusr[i]; break;
        //    case Arm7Mode.FIQ: for (uint i = 0; i < 7; i++) R[8 + i] = Rfiq[i]; break;
        //    case Arm7Mode.SVC: for (uint i = 0; i < 2; i++) R[13 + i] = Rsvc[i]; break;
        //    case Arm7Mode.ABT: for (uint i = 0; i < 2; i++) R[13 + i] = Rabt[i]; break;
        //    case Arm7Mode.IRQ: for (uint i = 0; i < 2; i++) R[13 + i] = Rirq[i]; break;
        //    case Arm7Mode.UND: for (uint i = 0; i < 2; i++) R[13 + i] = Rund[i]; break;
        //}

        //if ((Arm7Mode)Mode == Arm7Mode.FIQ)
        //    for (uint i = 0; i < 5; i++) R[8 + i] = Rusr[i];

        Mode = (uint)mode;
    }

    public uint[] Rusr = new uint[7];
    public uint[] Rfiq = new uint[7];
    public uint[] Rsvc = new uint[2];
    public uint[] Rabt = new uint[2];
    public uint[] Rirq = new uint[2];
    public uint[] Rund = new uint[2];

    internal uint GetCPSR()
    {
        uint val = 0;

        if (Negative) val = BitSet(val, 31);
        if (Zero) val = BitSet(val, 30);
        if (Carry) val = BitSet(val, 29);
        if (Overflow) val = BitSet(val, 28);
        if (Sticky) val = BitSet(val, 27);

        if (IRQDisable) val = BitSet(val, 7);
        if (FIQDisable) val = BitSet(val, 6);
        if (ThumbState) val = BitSet(val, 5);

        val |= GetMode();
        return val;
    }

    public uint GetMode()
    {
        return (uint)Mode;
    }

    public static uint BitSet(uint i, byte bit)
    {
        return (uint)(i | (uint)(1 << bit));
    }

    internal void ReloadQueue()
    {
        if (ThumbState)
        {
            if (GameStart.Ins.TestThumbIndex == 1)
                Thumb.thumb.BeginExecution();
            else
                ThumbCore.thumbCore.BeginExecution();

        }
        else
        {
            if (GameStart.Ins.isGbaArm)
                OptimeGBA.Arm.BeginExecution();
            
        }
    }

    internal void EnterException(uint sVC, int v1, bool v2, bool v3)
    {
        throw new NotImplementedException();
    }

    internal void Error(string v)
    {
        UnityEngine.Debug.LogError(v);
    }
}

public delegate int arm_inst_func_t(cpu_state_t st, uint inst); //arm指令处理函数